package com.xuexiang.xui_lib.component.progress.materialprogressbar;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrHelper;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Arc;
import ohos.agp.render.Canvas;
import ohos.agp.render.LinearShader;
import ohos.agp.render.Paint;
import ohos.agp.render.Path;
import ohos.agp.render.PathEffect;
import ohos.agp.render.Shader;
import ohos.agp.utils.Color;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.utils.Point;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.eventhandler.EventRunner;

import com.xuexiang.xui_lib.component.textview.marqueen.WeakHandler;

/**
 * 自定义圆形ProgressBar
 *
 * @since 2021-05-08
 */
public class MaterialCircleprogress extends MaterialProgressBar {
    private static final String COLOR_START = "#009ad6";
    /**
     * the type of animation
     */
    private int mAnimateType = 0;
    /**
     * the progress of start point
     */
    private float mStartProgress = 0;
    /**
     * the progress of end point
     */
    //private float mEndProgress = 60;
    /**
     * the color of start progress
     */
    private Color mStartColor;
    /**
     * the color of end progress
     */
    private Color mEndColor;
    /**
     * has track of moving or not
     */
    private boolean trackEnabled;
    /**
     * filling the inner space or not
     */
    private boolean fillEnabled;
    /**
     * the stroke width of Track
     */
    private int mTrackWidth;
    /**
     * the stroke width of progress
     */
    private int mProgressWidth;
    /**
     * the size of inner text
     */
    private int mProgressTextSize;
    /**
     * the color of inner text
     */
    private Color mProgressTextColor;
    /**
     * the circle of progress broken or not
     */
    private boolean circleBroken;
    /**
     * the color of progress track
     */
    private Color mTrackColor;
    /**
     * the duration of progress moving
     */
    private int mProgressDuration = 3000;
    /**
     * show the inner text or not
     */
    private boolean textVisibility;

    /**
     * the animator of progress moving
     */
    private AnimatorValue progressAnimator;
    /**
     * the progress of moving
     */
    private float moveProgress = 0;
    /**
     * the paint of drawing progress
     */
    private Paint progressPaint;
    /**
     * the paint of drawing track
     */
    private Paint trackPaint;
    /**
     * the gradient of color
     */
    private LinearShader mShader;
    /**
     * the oval's rect shape
     */
    private RectFloat mOval;

    private CircleProgressUpdateListener mUpdateListener;

    /**
     * the path of scale zone
     */
    private Path mScaleZonePath;
    /**
     * the width of each scale zone
     */
    private float mScaleZoneWidth;
    /**
     * the length of each scale zone
     */
    private float mScaleZoneLength;
    /**
     * the padding of scale zones
     */
    private int mScaleZonePadding;
    /**
     * open draw the scale zone or not
     */
    private boolean isGraduated = false;
    /**
     * the radius of scale zone corner
     */
    private int mScaleZoneCornerRadius = 0;

    private Paint secondProgressPaint;
    private Color secondColor;
    private float secondMoveProgress;
    private boolean indeterminate;
    private float indeterminateStart = 0;
    private boolean isLoopAnimate;
    private boolean isDynamic;
    private float dynamicStart = 0;
    private float dynamicSecondProgress = 0;
    private PathEffect pathEffect;

    /**
     * 构造函数
     *
     * @param context 上下文
     */
    public MaterialCircleprogress(Context context) {
        super(context);
        initAttrs(context, null);
    }

    /**
     * 构造函数
     *
     * @param context 上下文
     * @param attrSet 自定义属性
     */
    public MaterialCircleprogress(Context context, AttrSet attrSet) {
        super(context, attrSet);
        initAttrs(context, attrSet);
    }

    /**
     * 构造函数
     *
     * @param context 上下文
     * @param attrSet 自定义属性
     * @param styleName 主题名称
     */
    public MaterialCircleprogress(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        initAttrs(context, attrSet);
    }

    /**
     * 构造函数
     *
     * @param context 上下文
     * @param attrSet 自定义属性
     * @param resId 资源ID
     */
    public MaterialCircleprogress(Context context, AttrSet attrSet, int resId) {
        super(context, attrSet, resId);
        initAttrs(context, attrSet);
    }

    private void initAttrs(Context context, AttrSet attrSet) {
        if (attrSet != null) {
            if (attrSet.getAttr("progress").isPresent()) {
                moveProgress = attrSet.getAttr("progress").get().getFloatValue();
            } else {
                moveProgress = 0;
            }
            if (attrSet.getAttr("track_width").isPresent()) {
                mTrackWidth = attrSet.getAttr("track_width").get().getIntegerValue();
            } else {
                mTrackWidth = AttrHelper.vp2px(5, getContext());
            }
            if (attrSet.getAttr("progress_width").isPresent()) {
                mProgressWidth = AttrHelper.vp2px(attrSet.getAttr("progress_width").get().getIntegerValue(),
                    getContext());
            } else {
                mProgressWidth = AttrHelper.vp2px(5, getContext());
            }
            if (attrSet.getAttr("start_progress").isPresent()) {
                mStartProgress = attrSet.getAttr("start_progress").get().getFloatValue();
            } else {
                mStartProgress = 0;
            }
            if (attrSet.getAttr("end_progress").isPresent()) {
                //mEndProgress = attrSet.getAttr("end_progress").get().getFloatValue();
            } else {
                //mEndProgress = 0;
            }
            if (attrSet.getAttr("start_color").isPresent()) {
                mStartColor = attrSet.getAttr("start_color").get().getColorValue();
            } else {
                mStartColor = new Color(Color.getIntColor(COLOR_START));
            }
            if (attrSet.getAttr("second_color").isPresent()) {
                secondColor = attrSet.getAttr("second_color").get().getColorValue();
            } else {
                secondColor = new Color(Color.getIntColor("#90d7ec"));
            }
            if (attrSet.getAttr("second_progress").isPresent()) {
                dynamicSecondProgress = secondMoveProgress = attrSet.getAttr("second_progress").get().getFloatValue();
            } else {
                dynamicSecondProgress = secondMoveProgress = 0;
            }

            if (attrSet.getAttr("end_color").isPresent()) {
                mEndColor = attrSet.getAttr("end_color").get().getColorValue();
            } else {
                mEndColor = new Color(Color.getIntColor(COLOR_START));
            }
            if (attrSet.getAttr("isFilled").isPresent()) {
                fillEnabled = attrSet.getAttr("isFilled").get().getBoolValue();
            } else {
                fillEnabled = false;
            }
            if (attrSet.getAttr("isTracked").isPresent()) {
                trackEnabled = attrSet.getAttr("isTracked").get().getBoolValue();
            } else {
                trackEnabled = false;
            }
            if (attrSet.getAttr("circle_broken").isPresent()) {
                circleBroken = attrSet.getAttr("circle_broken").get().getBoolValue();
            } else {
                circleBroken = false;
            }
            if (attrSet.getAttr("textColor").isPresent()) {
                mProgressTextColor = attrSet.getAttr("textColor").get().getColorValue();
            } else {
                mProgressTextColor = Color.BLACK;
            }
            if (attrSet.getAttr("textSize").isPresent()) {
                mProgressTextSize = AttrHelper.fp2px(attrSet.getAttr("textSize").get().getIntegerValue(), getContext());
            } else {
                mProgressTextSize = AttrHelper.fp2px(12, getContext());
            }

            if (attrSet.getAttr("animate_type").isPresent()) {
                mAnimateType = attrSet.getAttr("animate_type").get().getIntegerValue();
            } else {
                mAnimateType = AnimatorValue.CurveType.ACCELERATE_DECELERATE;
            }

            if (attrSet.getAttr("track_color").isPresent()) {
                mTrackColor = attrSet.getAttr("track_color").get().getColorValue();
            } else {
                mTrackColor = new Color(Color.getIntColor("#afdfe4"));
            }
            if (attrSet.getAttr("textVisibility").isPresent()) {
                textVisibility = attrSet.getAttr("textVisibility").get().getBoolValue();
            } else {
                textVisibility = false;
            }

            if (attrSet.getAttr("duration").isPresent()) {
                mProgressDuration = attrSet.getAttr("duration").get().getIntegerValue();
            } else {
                mProgressDuration = 3000;
            }

            if (attrSet.getAttr("scaleZone_length").isPresent()) {
                mScaleZoneLength = AttrHelper.vp2px(attrSet.getAttr("scaleZone_length").get().getIntegerValue(), getContext());
            } else {
                mScaleZoneLength = AttrHelper.vp2px(22, getContext());
            }

            if (attrSet.getAttr("scaleZone_width").isPresent()) {
                mScaleZoneWidth = AttrHelper.vp2px(attrSet.getAttr("scaleZone_width").get().getIntegerValue(), getContext());
            } else {
                mScaleZoneWidth = AttrHelper.vp2px(6, getContext());
            }
            if (attrSet.getAttr("scaleZone_padding").isPresent()) {
                mScaleZonePadding = AttrHelper.vp2px(attrSet.getAttr("scaleZone_padding").get().getIntegerValue(), getContext());
            } else {
                mScaleZonePadding = AttrHelper.vp2px(16, getContext());
            }
            if (attrSet.getAttr("scaleZone_corner_radius").isPresent()) {
                mScaleZoneCornerRadius = AttrHelper.vp2px(attrSet.getAttr("scaleZone_corner_radius").get().getIntegerValue(), getContext());
            } else {
                AttrHelper.vp2px(8, getContext());
            }
            if (attrSet.getAttr("isGraduated").isPresent()) {
                isGraduated = attrSet.getAttr("isGraduated").get().getBoolValue();
            } else {
                isGraduated = false;
            }
            if (attrSet.getAttr("indeterminate").isPresent()) {
                indeterminate = attrSet.getAttr("indeterminate").get().getBoolValue();
            } else {
                indeterminate = false;
            }

            if (attrSet.getAttr("isLoopAnimate").isPresent()) {
                isLoopAnimate = attrSet.getAttr("isLoopAnimate").get().getBoolValue();
            } else {
                isLoopAnimate = false;
            }
            if (attrSet.getAttr("isDynamic").isPresent()) {
                isDynamic = attrSet.getAttr("isDynamic").get().getBoolValue();
            } else {
                isDynamic = false;
            }
            if (mProgressBackgroundTint != null) {
                mTrackColor = mProgressBackgroundTint;
            }
            if (mSecondaryProgressTint != null) {
                secondColor = mSecondaryProgressTint;
            }
            if (mProgressTint != null) {
                mStartColor = mProgressTint;
                mEndColor = mProgressTint;
            }
        } else {
            initValue();
        }
        initPaint();
        initListener();
    }

    private void initValue() {
        moveProgress = mStartProgress = 0;
        //mEndProgress = 0;
        dynamicSecondProgress = secondMoveProgress = 20;
        mStartColor = new Color(Color.getIntColor(COLOR_START));
        mEndColor = new Color(Color.getIntColor(COLOR_START));
        fillEnabled = false;
        trackEnabled = false;
        circleBroken = false;
        mProgressTextColor = Color.BLACK;
        mProgressTextSize = AttrHelper.fp2px(12, getContext());
        mTrackWidth = AttrHelper.vp2px(5, getContext());
        mProgressWidth = AttrHelper.vp2px(5, getContext());
        mAnimateType = AnimatorValue.CurveType.ACCELERATE_DECELERATE;
        mTrackColor = new Color(Color.getIntColor("#afdfe4"));
        textVisibility = false;
        mProgressDuration = 3000;
        mScaleZoneLength = AttrHelper.vp2px(22, getContext());
        mScaleZoneWidth = AttrHelper.vp2px(6, getContext());
        mScaleZonePadding = AttrHelper.vp2px(16, getContext());
        mScaleZoneCornerRadius = AttrHelper.vp2px(8, getContext());
        isGraduated = false;
        secondColor = new Color(Color.getIntColor("#90d7ec"));
        indeterminate = false;
        isLoopAnimate = false;
        isDynamic = false;
    }

    private void initPaint() {

        progressPaint = new Paint();
        progressPaint.setStyle(Paint.Style.STROKE_STYLE);
        progressPaint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);
        progressPaint.setAntiAlias(true);
        progressPaint.setStrokeWidth(mProgressWidth);


        trackPaint = new Paint();
        trackPaint.setAntiAlias(true);
        trackPaint.setStyle(Paint.Style.STROKE_STYLE);
        trackPaint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);
        trackPaint.setStrokeWidth(mTrackWidth);

        mScaleZonePath = new Path();


        secondProgressPaint = new Paint();
        secondProgressPaint.setStyle(Paint.Style.STROKE_STYLE);
        secondProgressPaint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);
        secondProgressPaint.setAntiAlias(true);
        secondProgressPaint.setStrokeWidth(mProgressWidth);

        drawScaleZones(isGraduated);
    }


    private void initListener() {

        setEstimateSizeListener(new EstimateSizeListener() {
            @Override
            public boolean onEstimateSize(int widthMeasureSpec, int heightMeasureSpec) {

                int width = EstimateSpec.getSize(widthMeasureSpec);
                int height = EstimateSpec.getSize(heightMeasureSpec);
                setEstimatedSize(
                    EstimateSpec.getChildSizeWithMode(width, width, EstimateSpec.NOT_EXCEED),
                    EstimateSpec.getChildSizeWithMode(height, height, EstimateSpec.NOT_EXCEED)
                );
                updateTheTrack();

                Point[] points = new Point[]{new Point(mOval.left - 200, mOval.top - 200),
                    new Point(mOval.right + 20, mOval.bottom + 20)};
                Color[] colors = new Color[]{mStartColor, mEndColor};
                mShader = new LinearShader(points, new float[]{}, colors, Shader.TileMode.CLAMP_TILEMODE);

                RectFloat mScaleZoneRect = new RectFloat(0, 0, mScaleZoneWidth, mScaleZoneLength);
                mScaleZonePath.addRoundRect(mScaleZoneRect, mScaleZoneCornerRadius, mScaleZoneCornerRadius, Path.Direction.CLOCK_WISE);

                return true;
            }
        });

        addDrawTask(new DrawTask() {
            @Override
            public void onDraw(Component component, Canvas canvas) {

                drawTrack(canvas);

                drawProgress(canvas);

                drawProgressText(canvas);
            }
        });
        setBindStateChangedListener(new BindStateChangedListener() {
            @Override
            public void onComponentBoundToWindow(Component component) {
                if (isLoopAnimate)
                    startProgressAnimation();
            }

            @Override
            public void onComponentUnboundFromWindow(Component component) {

            }
        });
    }


    /**
     * draw the track(moving background)
     *
     * @param canvas mCanvas
     */
    private void drawTrack(Canvas canvas) {
        if (trackEnabled) {
            if (!mShowBackground) {
                return;
            }
            trackPaint.setShader(null, Paint.ShaderType.LINEAR_SHADER);
            trackPaint.setColor(mTrackColor);
            initTrack(canvas, fillEnabled);
        }
    }

    private void drawProgress(Canvas canvas) {
        progressPaint.setShader(mShader, Paint.ShaderType.SWEEP_SHADER);
        //updateTheTrack();
        initProgressDrawing(canvas, fillEnabled);
    }

    private void drawScaleZones(boolean isGraduated) {
        if (isGraduated) {
            if (pathEffect == null) {
                pathEffect = new PathEffect(mScaleZonePath, mScaleZonePadding, 0, PathEffect.Style.ROTATE_STYLE);
            }
            progressPaint.setPathEffect(pathEffect);
        } else {
            pathEffect = null;
            progressPaint.setPathEffect(null);
        }
    }

    /**
     * init for track view
     *
     * @param canvas mCanvas
     * @param isFilled whether filled or not
     */
    private void initTrack(Canvas canvas, boolean isFilled) {
        if (isFilled) {
            trackPaint.setStyle(Paint.Style.FILL_STYLE);
        } else {
            trackPaint.setStyle(Paint.Style.STROKE_STYLE);
        }
        if (circleBroken) {
            canvas.drawArc(mOval, new Arc(135, 270, isFilled), trackPaint);
        } else {
            canvas.drawArc(mOval, new Arc(90, 360, isFilled), trackPaint);
        }
    }

    /**
     * draw the progress text
     *
     * @param canvas mCanvas
     */
    private void drawProgressText(Canvas canvas) {
        if (textVisibility) {
            Paint mTextPaint = new Paint();
            mTextPaint.setAntiAlias(true);
            mTextPaint.setStyle(Paint.Style.FILL_STYLE);
            mTextPaint.setTextSize(mProgressTextSize);
            mTextPaint.setColor(mProgressTextColor);
            mTextPaint.setTextAlign(LayoutAlignment.CENTER);

            String progressText = ((int) moveProgress) + "%";
            float x = (getWidth() + getPaddingLeft() - getPaddingRight()) >> 1;
            float y = (getHeight() + getPaddingTop() - getPaddingBottom() - (mTextPaint.descent() + mTextPaint.ascent())) / 2;
            canvas.drawText(mTextPaint, progressText, x, y);
        }

    }

    /**
     * set progress animate type
     *
     * @param type anim type
     */
    public void setAnimateType(int type) {
        this.mAnimateType = type;
    }

    /**
     * set move progress
     *
     * @param progress progress of moving
     */
    public void setProgress(float progress) {
        this.moveProgress = progress;
        refreshTheView();
    }

    public float getProgress() {
        return this.moveProgress;
    }

    /**
     * set start progress
     *
     * @param startProgress start progress
     */
    public void setStartProgress(float startProgress) {
        if (startProgress < 0 || startProgress > 100) {
            throw new IllegalArgumentException("Illegal progress value, please change it!");
        }
        this.mStartProgress = startProgress;
        this.moveProgress = mStartProgress;
        refreshTheView();
    }

    /**
     * set end progress
     *
     * @param endProgress end progress
     */
    public void setEndProgress(float endProgress) {
        if (endProgress < 0 || endProgress > 100) {
            throw new IllegalArgumentException("Illegal progress value, please change it!");
        }
        //this.mEndProgress = endProgress;
        refreshTheView();

    }

    public void setSecondColor(Color color) {
        this.secondColor = color;

    }

    public void setSecondMoveProgress(float secondMoveProgress) {
        this.secondMoveProgress = secondMoveProgress;
    }

    /**
     * set start color
     *
     * @param startColor start point color
     */
    public void setStartColor(Color startColor) {
        this.mStartColor = startColor;
        updateTheTrack();
        Point[] points = new Point[]{new Point(mOval.left - 200, mOval.top - 200),
            new Point(mOval.right + 20, mOval.bottom + 20)};
        Color[] colors = new Color[]{mStartColor, mEndColor};
        mShader = new LinearShader(points, new float[]{}, colors, Shader.TileMode.CLAMP_TILEMODE);
        refreshTheView();
    }

    /**
     * set end color
     *
     * @param endColor end point color
     */
    public void setEndColor(Color endColor) {
        this.mEndColor = endColor;
        updateTheTrack();
        Point[] points = new Point[]{new Point(mOval.left - 200, mOval.top - 200),
            new Point(mOval.right + 20, mOval.bottom + 20)};
        Color[] colors = new Color[]{mStartColor, mEndColor};
        mShader = new LinearShader(points, new float[]{}, colors, Shader.TileMode.CLAMP_TILEMODE);
        refreshTheView();
    }

    /**
     * set the width of progress stroke
     *
     * @param width stroke
     */
    public void setTrackWidth(int width) {
        mTrackWidth = AttrHelper.vp2px(width, getContext());
        trackPaint.setStrokeWidth(width);
        updateTheTrack();
        refreshTheView();
    }

    /**
     * set the width of progress stroke
     *
     * @param width stroke
     */
    public void setProgressWidth(int width) {
        mProgressWidth = AttrHelper.vp2px(width, getContext());
        progressPaint.setStrokeWidth(width);
        refreshTheView();
    }

    /**
     * set text size for inner text
     *
     * @param size text size
     */
    public void setProgressTextSize(int size) {
        mProgressTextSize = AttrHelper.fp2px(size, getContext());
        refreshTheView();
    }

    /**
     * set text color for progress text
     *
     * @param textColor
     */
    public void setProgressTextColor(Color textColor) {
        this.mProgressTextColor = textColor;
    }

    /**
     * set duration of progress moving
     *
     * @param duration
     */
    public void setProgressDuration(int duration) {
        this.mProgressDuration = duration;
    }

    /**
     * set track for progress
     *
     * @param trackAble whether track or not
     */
    public void setTrackEnabled(boolean trackAble) {
        this.trackEnabled = trackAble;
        refreshTheView();
    }

    /**
     * set track color for progress background
     *
     * @param color bg color
     */
    public void setTrackColor(Color color) {
        if (!mShowBackground) {
            return;
        }
        this.mTrackColor = color;
        refreshTheView();
    }

    /**
     * set content for progress inner space
     *
     * @param fillEnabled whether filled or not
     */
    public void setFillEnabled(boolean fillEnabled) {
        this.fillEnabled = fillEnabled;
        refreshTheView();
    }

    /**
     * set the broken circle for progress
     *
     * @param isBroken the circle broken or not
     */
    public void setCircleBroken(boolean isBroken) {
        this.circleBroken = isBroken;
        refreshTheView();
    }

    /**
     * set the scale zone type for progress view
     *
     * @param isGraduated have scale zone or not
     */
    public void setGraduatedEnabled(final boolean isGraduated) {
        this.isGraduated = isGraduated;

        new WeakHandler(EventRunner.current()).post(new Runnable() {
            @Override
            public void run() {
                drawScaleZones(isGraduated);
            }
        });
    }

    /**
     * set the scale zone width for it
     *
     * @param zoneWidth each zone 's width
     */
    public void setScaleZoneWidth(float zoneWidth) {
        this.mScaleZoneWidth = AttrHelper.vp2px(zoneWidth, getContext());
    }

    /**
     * set the scale zone length for it
     *
     * @param zoneLength each zone 's length
     */
    public void setScaleZoneLength(float zoneLength) {
        this.mScaleZoneLength = AttrHelper.vp2px(zoneLength, getContext());
    }

    /**
     * set each zone's distance
     *
     * @param zonePadding distance
     */
    public void setScaleZonePadding(int zonePadding) {
        this.mScaleZonePadding = AttrHelper.vp2px(zonePadding, getContext());
    }

    /**
     * set corner radius for each zone
     *
     * @param cornerRadius round rect zone's corner
     */
    public void setScaleZoneCornerRadius(int cornerRadius) {
        this.mScaleZoneCornerRadius = AttrHelper.vp2px(cornerRadius, getContext());
    }

    /**
     * set the visibility for progress inner text
     *
     * @param visibility text visible or not
     */
    public void setProgressTextVisibility(boolean visibility) {
        this.textVisibility = visibility;
    }

    public void setIsLoopAinimate(boolean isLoopAnimate) {
        this.isLoopAnimate = isLoopAnimate;
    }

    public void setIndeterminate(boolean indeterminate) {
        this.indeterminate = indeterminate;
    }

    /**
     * start the progress's moving
     */
    public void startProgressAnimation() {
        progressAnimator = new AnimatorValue(); // .ofFloat(this, "progress", mStartProgress, mEndProgress);
        progressAnimator.setCurveType(mAnimateType);
        progressAnimator.setDuration(mProgressDuration);

        progressAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float progress) {

                if (mUpdateListener != null) {
                    mUpdateListener.onCircleProgressUpdate(MaterialCircleprogress.this, progress);
                }

                moveProgress = progress * 100;
                if (indeterminate) {
                    indeterminateStart = (progress * 100) * progress;
                }
                if (isDynamic) {
                    dynamicStart += progress;
                    dynamicSecondProgress += progress;
                }
                invalidate();
            }
        });


        progressAnimator.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {
                if (mUpdateListener != null) {
                    mUpdateListener.onCircleProgressStart(MaterialCircleprogress.this);
                }
            }

            @Override
            public void onStop(Animator animator) {

            }

            @Override
            public void onCancel(Animator animator) {

            }

            @Override
            public void onEnd(Animator animator) {
                if (isDynamic) {
                    dynamicStart = 0;
                    dynamicSecondProgress = secondMoveProgress;
                }
                if (mUpdateListener != null) {
                    mUpdateListener.onCircleProgressFinished(MaterialCircleprogress.this);
                }
                if (isLoopAnimate) {
                    progressAnimator.start();
                }
            }

            @Override
            public void onPause(Animator animator) {

            }

            @Override
            public void onResume(Animator animator) {

            }
        });

        progressAnimator.start();
    }

    /**
     * stop the progress moving
     */
    public void stopProgressAnimation() {
        if (progressAnimator != null) {
            isLoopAnimate = false;
            progressAnimator.cancel();
            progressAnimator = null;
        }
    }

    /**
     * refresh the layout
     */
    private void refreshTheView() {
        invalidate();
        postLayout();
    }

    /**
     * update the oval progress track
     */
    private void updateTheTrack() {
        if (mOval != null) {
            mOval = null;
        }

        mOval = new RectFloat(getPaddingLeft() + mTrackWidth, getPaddingTop() + mTrackWidth,
            getWidth() - getPaddingRight() - mTrackWidth,
            getHeight() - getPaddingBottom() - mTrackWidth);


    }

    /**
     * init the circle progress drawing
     *
     * @param canvas mCanvas
     * @param isFilled filled or not
     */
    private void initProgressDrawing(Canvas canvas, boolean isFilled) {
        if (isFilled) {
            progressPaint.setStyle(Paint.Style.FILL_STYLE);
        } else {
            progressPaint.setStyle(Paint.Style.STROKE_STYLE);
        }
        secondProgressPaint.setColor(secondColor);

        drawIndeterminate(canvas, isFilled);
        drawDynamic(canvas, isFilled);
        drawNormal(canvas, isFilled);
    }

    private void drawNormal(Canvas canvas, boolean isFilled) {
        if (indeterminate || isDynamic) {
            return;
        }
        if (circleBroken) {
            if (secondMoveProgress > 0) {
                canvas.drawArc(mOval, new Arc(135 + mStartProgress * 2.7f, ((secondMoveProgress + moveProgress) - mStartProgress) * 2.7f, isFilled), secondProgressPaint);
            }
            canvas.drawArc(mOval, new Arc(135 + mStartProgress * 2.7f, (moveProgress - mStartProgress) * 2.7f, isFilled), progressPaint);
        } else {
            if (secondMoveProgress > 0) {
                canvas.drawArc(mOval, new Arc(270 + mStartProgress * 3.6f, ((secondMoveProgress + moveProgress) - mStartProgress) * 3.6f, isFilled), secondProgressPaint);
            }
            canvas.drawArc(mOval, new Arc(270 + mStartProgress * 3.6f, (moveProgress - mStartProgress) * 3.6f, isFilled), progressPaint);
        }
    }

    private void drawIndeterminate(Canvas canvas, boolean isFilled) {
        if (!indeterminate) {
            return;
        }

        if (secondMoveProgress > 0) {
            canvas.drawArc(mOval, new Arc(270 + mStartProgress * 3.6f, ((secondMoveProgress + moveProgress) - indeterminateStart) * 3.6f, isFilled), secondProgressPaint);
        }
        canvas.drawArc(mOval, new Arc(340 + indeterminateStart * 3.6f, (moveProgress - indeterminateStart) * 7.2f, isFilled), progressPaint);

    }

    private void drawDynamic(Canvas canvas, boolean isFilled) {
        if (!isDynamic) {
            return;
        }

        if (secondMoveProgress > 0) {
            canvas.drawArc(mOval, new Arc(270 + dynamicStart * 3.6f, (moveProgress + dynamicSecondProgress) * 3.6f, isFilled), secondProgressPaint);
        }
        canvas.drawArc(mOval, new Arc(270 + dynamicStart * 3.6f, moveProgress * 3.6f, isFilled), progressPaint);

    }

    /**
     * 进度条更新监听
     */
    public interface CircleProgressUpdateListener {
        /**
         * 进度条开始更新
         *
         * @param component
         */
        void onCircleProgressStart(Component component);

        /**
         * 进度条更新中
         *
         * @param component
         * @param progress
         */
        void onCircleProgressUpdate(Component component, float progress);

        /**
         * 进度条更新结束
         *
         * @param component
         */
        void onCircleProgressFinished(Component component);
    }

    /**
     * set the progress update listener for progress view
     *
     * @param listener update listener
     */
    public void setProgressViewUpdateListener(CircleProgressUpdateListener listener) {
        this.mUpdateListener = listener;
    }

}
